import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
/**
 * 描述：根据json判断相应接口字段是否缺少，特殊字段是否符合格式，为空字段，字段类型等<br/>
 * 创建时间：2018/8/1<br/>
 *
 * @author $kai zhang$
 */
public class FieldAmalyticalUtil {
    private List<String> keys = new ArrayList<>();//配置文件里的所有key
    private Map<String, String> filed = new HashMap<>();//配置文件里的所有字段
    private final Map<String, String> chufiled = new HashMap<>();//获取出参的所有字段
    private  List<String> comkeys =  new ArrayList<>();//共同包含的字段
    private String uncomkeys = "";//没传入的字段
    private String dataFiekd = "";  //出参所有字段信息
    private String allcontent = "\n\t,数组" + ",字段名,值,类型\n\t";//生成csv的表头
    private List<String> allkeys = new ArrayList<>();//出参的所有字段
    private String novalue_key = "";
    private String findsome = "";

    /**
     * 检查接口字段是否对应
     *
     * @param fileUrl 文件所在路径
     * @param type    接口类型  op-0,ip-1,mr-2,inspect-3
     * @return
     */
    public String checkInterfaceThginseng(String fileUrl, Integer type) {

        String allSomething = "";//获取数据内容

        try {
            File file = new File(fileUrl);
            if (file.isFile() && file.exists()) {
                InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "utf-8");
                BufferedReader br = new BufferedReader(isr);
                String lineTxt = null;
                while ((lineTxt = br.readLine()) != null) {
                    allSomething += lineTxt + "  ";
                }
                br.close();
            } else {
                System.out.println("文件不存在!");
            }
        } catch (Exception e) {
            System.out.println("文件读取错误!");
        }
        //查找字段是否对应
       getJsonCheckType(JSONObject.fromObject(allSomething), type,fileUrl);
        //判断特殊字符
        try {
            checkSpecialFiled(chufiled);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        dataFiekd += "\n\t出参内容如下:" + checkField(JSONObject.fromObject(allSomething));//查找便利内容
        creatCSV(fileUrl, dataFiekd);//所有数据存入

        return dataFiekd;
    }

    /**
     * 判断字段值是否为空,递归查询
     *
     * @param content
     * @return
     */
    public String checkField(Object content) {
//====================================================获取字段内容，筛选是否为空========
        if (content instanceof JSONObject) {
            JSONObject jsonObject = JSONObject.fromObject(content);
            Iterator<String> opfild = jsonObject.keys();
            while (opfild.hasNext()) {
                String key = opfild.next();
                Object value = jsonObject.get(key);
                allkeys.add(key);
                if (value instanceof JSONArray) {
                    System.out.println("进---------------," + key);
                    allcontent += "," + key + "开始,,,数组\n\t";              //判断是否为数组
                    JSONArray objArray = JSONArray.fromObject(value);
                    for (int i = 0; i < objArray.size(); i++) {
                        JSONObject job = objArray.getJSONObject(i); // 遍历 jsonarray 数组，把每一个对象转成 json 对象
                        checkField(job);                          //递归
                    }
                    allcontent += "," + key + "结束,,,数组\n\t";
                    System.out.println("出---------------," + key);
                } else {

                    if (value instanceof String) {                  //是否是字符串类型
                        String value1 = (String) value;
                        if (value1.equals("")) {                    //字段是否为空
                            novalue_key += key + " ";
                            allcontent += ",," + key + ",空\n\t";
                            System.out.println(key + ",空");
                        } else if (value1.matches("[0-9]*")) { //字段是否为数字
                            novalue_key += key + " ";
                            findsome += key + " ";
                            allcontent += ",," + key + "," + value1 + ",数值\n\t";
                            System.out.println(key + "," + value1);
                        } else {                                      //字段是否为字符串
                            novalue_key += key + " ";
                            findsome += key + " ";
                            allcontent += ",," + key + "," + value1 + ",字符串\n\t";
                            System.out.println(key + "," + value1);
                        }
                    } else if (value instanceof Boolean)              //字段是否为布尔类型
                    {
                        novalue_key += key + " ";
                        allcontent += ",," + key + "," + value + ",布尔类\n\t";
                        System.out.println(key + "," + value);
                    }
                }
            }
        }
        return allcontent;
    }
    /**
     * 根据筛选的内容保存成csv文件
     *
     * @return
     */
    public static void creatCSV(String path, String content) {
        String[] paths = path.split("\\.");
        OutputStreamWriter outputStreamWriter = null;
        BufferedWriter bufferedWriter = null;
        File f = null;
        try {
            //如果文件存在，则追加内容；如果文件不存在，则创建文件
            f = new File(paths[0] + "_" + new Date().getTime() + ".csv");
            outputStreamWriter = new OutputStreamWriter(new FileOutputStream(f), "gbk");
            bufferedWriter = new BufferedWriter(outputStreamWriter);
            bufferedWriter.write(content);
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            bufferedWriter.flush();
            outputStreamWriter.flush();
            bufferedWriter.close();
            outputStreamWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
//               File   fs=new File(paths[0]+".csv");
//                f.renameTo(fs);
    }

    /**
     * 查找出参是否缺乏字段
     *
     * @param type
     * @param content
     */
    public void getJsonCheckType(JSONObject content, Integer type,String fileurl) {
        Properties properties = new Properties();
        String file = "";
         //        ================================获取配置文件标准的字段个数以及字段类型
        try {
            if (type == 0) {
                file = "/Op.properties";
                System.out.println("-------------------------------------调用op--------------------------------------");
            } else if (type == 1) {
                file = "/Ip.properties";
                System.out.println("-------------------------------------调用ip--------------------------------------");
            }else if(type==2){
                file = "/Mr.properties";
                System.out.println("-------------------------------------调用Mr--------------------------------------");
            }
            else if(type==3){
                file = "/Inspect.properties";
                System.out.println("-------------------------------------调用Inspect--------------------------------------");
            }
            else{
                dataFiekd=checkField(content);//查找便利内容
                creatCSV(fileurl, dataFiekd);//所有数据存入
                System.exit(0);
            }
            properties.load(new InputStreamReader(new FileInputStream(Class.class.getClass().getResource("/").getPath() + file), "utf-8"));
            ///获取配置文件内容
            Iterator<String> it = properties.stringPropertyNames().iterator();
            while (it.hasNext()) {
                String key_p = it.next();
                //根据配置文件查取字段
                keys.add(key_p);
                //获取配置文件字段类型
                filed.put(key_p, properties.getProperty(key_p));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("配置文件里的key:-------------------");
        System.out.println();
        //查询多少字段相等，comkeys
        getJsonCheckType(content);
        //删除相同字段
        removeJsonCheckType();
//        =========================没有传入的参数
        System.out.println("没有传入或多出的字段:-------------------");
        System.out.println(uncomkeys);
        dataFiekd += "\n\t\n\t\n\t" + "没有传入或多出的字段：";
        dataFiekd += "\n\t" + uncomkeys;
        System.out.println("没有传入或多出的字段:-------------------");
//        Iterator<String> opfild = content.keys();  //读取出参里的keys
//        while (opfild.hasNext()) {
//        String key=opfild.next();
//    }
//           String[] chu_key =allkeys.split(",");
//        for (int i=0;i<chu_key.length;i++) {
//            if (keys.contains(chu_key[i]))  //在配置文件keys里查找
//            {
//                keys = keys.replace(chu_key[i], "");   //把配置文件里的key 和接收的key对比，如果存在，则划掉
//            } else {
//                nofindfiled +=chu_key[i]+",";
//            }
//        }
    }

    /**
     * 找出和配置文件相等的出参字段名，递归生成
     *
     * @param content
     * @return
     */
    public void getJsonCheckType(JSONObject content) {
        Iterator<String> opfild = content.keys();
        while (opfild.hasNext()) {
            String key_c = opfild.next();
                if (chufiled.containsKey(key_c)) {    //判断是否已经添加过的项
                        chufiled.put(key_c + "_" + new Date().getTime(), content.getString(key_c));
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    chufiled.put(key_c,content.getString(key_c));
                }
            for (int i = 0; i < keys.size(); i++){
                if (keys.get(i).equals(key_c)) {  //遍历配置文件的key是否等于出参key
                    comkeys.add( key_c);           //找到相同的字段
                }
            }
//                      ===========================判断value是否还是数组
            Object value = content.get(key_c);
            if (value instanceof JSONArray) {
                JSONArray objArray = JSONArray.fromObject(value);
                for (int i = 0; i < objArray.size(); i++) {
                    JSONObject job = objArray.getJSONObject(i); // 遍历 jsonarray 数组，把每一个对象转成 json 对象
                    getJsonCheckType(job);                          //递归
                }

            }
        }
    }
    /**
     * 删除相等的字段名--------------------------------找出未传字段
     *
     * @return
     */
    public void removeJsonCheckType() {
        System.out.println("给出相等的字段：" + comkeys);
        for (int j = 0; j < comkeys.size(); j++) {
            keys.remove(comkeys.get(j));  //把配置文件里的key 和接收的key对比，如果存在，则划掉
        }
        for (String s : keys) {
            uncomkeys += ",," + s + ",\n\t";
        }

    }


    /**
     * 判断特殊附录字段
     */
    public void checkSpecialFiled(Map<String,String> map) throws NoSuchFieldException {
        dataFiekd+="\n\t判断特殊字段类型值是否符合规范:\n\t,,字段名称,是否规范,不规范的值\n\t";
        String[] gender={"0","1","2","9"};//性别
        String[] race={"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","55","56","90","99"};//民族
         String[] socialSecurityNm={"01","02","03","04","05","06","07","99"};//社保类别
        String[] certType={"01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","99"};//就诊类型
        String[] registerType={"0","1","2","3","4"};//挂号类别
        String[] costCategory={"01","02","03","04","05","06","07","99"};//患者性质
        String[] outpatientType={"0","1"};//患者类型
         String[] clientStatus={"01","02","03","04","05","06","07","08","09","10","11","12","13"};//患者现状
        String[] diagnosisLevel={"0","1"};//诊断级别
         String[] diagnosisResult={"0","1","2"};//治疗结果
         String[] itemClass={"01","02","03","04","08","09","10","11","12","13","14","15","17","18","19","20","23","24","30","31","32","33","34","35","99"};//医疗项目类别
        String[] medicalItemCat={"1","2","3","4","5","6","7","8","9","10","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","49","50","51","52","53","54","99"};//医疗明细类别
        String[] listCat={"1","2","3","4"};//医疗目录类别
        String[] insurLevel={"0","1","2"};//医疗项目等级
        String[] frequency={"QD","BID","TID","QID","Q30D","QW","Q2W","BIW","TIW","Q30M","Q1H","Q2H","Q3H","Q4H","Q5H","Q6H","Q8H","Q12H","Q72H","QM","QN","QON","ST","QOD","Q5D","Q10D","C12H","C24H","PRN","AC","AM","Q3D","99"};//使用频次
        String[] insurCatAdminLevel={"1","2","9"};//医保目录行政区划级别
        String[] drugDeliverType={"100","200","300","400","401","402","403","404","500","600","601","602","603","604","605","606","607","608","609","610","611","612","699","900"};//给药方式
        Map<String,String[]> map1=new HashMap<>();
        String[] settlementType={"00","01","02","03","99"};
        map1.put("settlementType",settlementType);//结算类别
        String[] medicalType={"00","01","99"};//医疗类别
        map1.put("medicalType",medicalType);
        String[] isInSocialSecurityFlg={"0","1"};//是否参加社保
        map1.put("isInSocialSecurityFlg",isInSocialSecurityFlg);
        String[] billType={"1","2"};//材料类型
        map1.put("billType",billType);
        String[] outOrInIdentify={"1","2","3","4","5"};//数据标识
        map1.put("outOrInIdentify",outOrInIdentify);
        String[] serviceClassification={"0","1","2"};//业务分类
        map1.put("serviceClassification",serviceClassification);
        String[] pnFlag={"0","1"};//标志
        map1.put("pnFlag",pnFlag);//标志
        String[] inHospitalSettlementType={"0","1"};//住院结算类别
        map1.put("inHospitalSettlementType",inHospitalSettlementType);
        String[] medicineCat={"0","1"};//药品区分
        map1.put("medicineCat",medicineCat);
        String[] drugCat={"0","1"};//药品种类
        map1.put("drugCat",drugCat);
        String[] ageUnit={"0","1","2"};//年龄单位
        map1.put("ageUnit",ageUnit);
        String[] isPrescription={"0","1"};//是否处方标识
        map1.put("isPrescription",isPrescription);
        String[] extraRecipeFlg={"0","1"};//处带处方标志
        map1.put("extraRecipeFlg",extraRecipeFlg);
        String[] insuranceCatAdminLevel={"1","2","9"};//医保目录行政区划级别
        map1.put("insuranceCatAdminLevel",insuranceCatAdminLevel);
        String[] herbFuFangSign={"1","2"};//草药单复方标志
        map1.put("herbFuFangSign",herbFuFangSign);
        String[] isRestricted={"0","1"};//限制用药标识
        map1.put("isRestricted",isRestricted);
        String[] origion={"国产","进口"};//产地
        map1.put("origion",origion);
        String[] diagnosisType={"0","1"};//诊断类型
        map1.put("diagnosisType",diagnosisType);
        map1.put("gender",gender);  //性别
        map1.put("race",race);      //民族
        map1.put("socialSecurityNm",socialSecurityNm);//社保类别
        map1.put("certType",certType);//就诊类型
        map1.put("registerType",registerType);//挂号类别
        map1.put("costCategory",costCategory);//患者性质
        map1.put("outpatientType",outpatientType);//患者类型
        map1.put("clientStatus",clientStatus);//患者现状
        map1.put("diagnosisLevel",diagnosisLevel);//诊断级别
        map1.put("diagnosisResult",diagnosisResult);//治疗结果
        map1.put("itemClass",itemClass);//医疗项目类别
        map1.put("medicalItemCat",medicalItemCat);//医疗明细类别
        map1.put("listCat",listCat);//医疗目录类别
        map1.put("insurLevel",insurLevel);//医疗项目等级
        map1.put("frequency",frequency);//使用频次
        map1.put("insurCatAdminLevel",insurCatAdminLevel);//医保目录行政区划级别
        map1.put("drugDeliverType",drugDeliverType);//给药方式

         checkSpecial(map,map1);
    }

    /**
     * 检查特殊字段值
     * @param map  出参
     * @param map1 规范
     */
    public void checkSpecial(Map<String,String> map, Map<String,String[]> map1)
    {
        Integer message=0;
        String aa="";
        String[] special={"serviceClassification","pnFlag","inHospitalSettlementType","medicineCat","drugCat","ageUnit","isPrescription","extraRecipeFlg","insuranceCatAdminLevel","herbFuFangSign","isRestricted","origion","diagnosisType","settlementType","medicalType","isInSocialSecurityFlg","billType","outOrInIdentify","gender","race","socialSecurityNm","certType","registerType","costCategory","outpatientType","clientStatus","diagnosisLevel","diagnosisResult","itemClass","medicalItemCat","listCat","insurLevel","frequency","insurCatAdminLevel","drugDeliverType"};
        for (int j=0;j<special.length;j++) {
            List<String> list=new ArrayList<>();
            //判断special里面的每个值是否包含多个
            Iterator it = map.entrySet().iterator();
            while(it.hasNext()) {
                Map.Entry<String, String> entry = (Map.Entry<String, String>)it.next();

                //&& entry.getKey().replace(special[j],"").startsWith("_")
                if (entry.getKey().indexOf(special[j]) != -1 ) {  //筛选出special里面key被多个包含的key
                        if (entry.getValue().indexOf("[") == -1) {
                            list.add(entry.getKey());
                        }

                    }
            }
            for (String s:list) {
                if (s.replace(special[j],"").startsWith("_") || s.equals(special[j])) {//如果是字段中包含多个，则判断是否
                    String val = map.get(s);   //  获取出参的值
                    String[] vals = map1.get(special[j]); //获取响应特殊字段的固定值
                    if (val != null || val != "") {
                        for (int i = 0; i < vals.length; i++) {
                            if (vals[i].toString().equals(val)) {
                                message = 1;
                                aa += ",," + s + ",是\n\t";
                                break;
                            }
                        }
                        if (message == 0) {
                            if (val.equals("")) {
                                aa += ",," + s + ",否,空\n\t";
                            } else {
                                aa += ",," + s + ",否," + val + "\n\t";
                            }
                        } else {
                            message = 0;
                        }
                    } else {
                        aa += ",," + s + ",否,空\n\t";
                    }
                }
            }
        }
        dataFiekd+=aa;
    }
}